/*************************************************************************
 *
 *  Copyright (C) 2013 Florian Dang <florian.coin@gmail.com>
 *
 *  This file is part of NatusVerse.
 *
 *  NatusVerse is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  NatusVerse is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with NatusVerse.  If not, see <http://www.gnu.org/licenses/>.
 *
 *************************************************************************/

#include "raytracer/objects/material.h"

#include <stdio.h>
#include <cmath>

namespace raytracer
{
using color::Color;
typedef unsigned int uint;

void Material::BrdfReflect(const Light& luminance, const float& coeff_brdf, Color& pixel_color)
{
	pixel_color.set_r(pixel_color.r() + static_cast<uint>(
		static_cast<float>(color_reflect().color_r()) * (coeff_brdf * luminance.intensity_r()))
		);
	pixel_color.set_g(pixel_color.g() + static_cast<uint>(
		static_cast<float>(color_reflect().color_g()) * (coeff_brdf * luminance.intensity_g()))
		);
	pixel_color.set_b(pixel_color.b() + static_cast<uint>(
		static_cast<float>(color_reflect().color_b()) * (coeff_brdf * luminance.intensity_b()))
		);
}

float Material::BrdfLambert(const Ray& ray_light , const Vector& vec_normal, const float& coeff_recurs_reflect) const
{
	float coeff_lambert = coeff_recurs_reflect * (ray_light.direction() * vec_normal);

	return coeff_lambert;
}


float Material::BrdfPhong(const Ray& ray_light, const Vector& vec_normal, const float& coeff_recurs_reflect, const Ray& ray_view) const
{
	float reflect = 2.0f * (ray_light.direction() * vec_normal);
	Vector vect_phong = ray_light.direction() - (reflect * vec_normal);
	float coeff_phong = std::max((vect_phong * ray_view.direction()), 0.0f);
	coeff_phong = specular() * powf(coeff_phong, rugosity()) * coeff_recurs_reflect;

	return coeff_phong;
}

float Material::BrdfBlinnPhong(const Ray& ray_light, const Vector& vec_normal, const float& coeff_recurs_reflect, const Ray& ray_view) const
{

	Vector vect_blinn = ray_light.direction() - ray_view.direction();
	vect_blinn.Normalize();
	float coeff_blinn = std::max((vect_blinn * vec_normal), 0.0f);
	coeff_blinn = specular() * powf(coeff_blinn, rugosity()) * coeff_recurs_reflect;

	return coeff_blinn;
}


float Material::Refraction(Ray ray_light, Vector vec_normal, float& coeff_recurs_refraction) const
{
	float coeff_beer = 0.0f;
	float refraction_index = coeff_refract();
	float n = coeff_recurs_refraction / refraction_index;

	float CosThetaI = -1.0f * (vec_normal * ray_light.direction());
	float SinThetaI = sqrtf(1.0 - CosThetaI * CosThetaI);
	float SinThetaT = n * SinThetaI;

	if(SinThetaT*SinThetaT < 1.0)
	{
		float CosThetaT = sqrt(1.0 - SinThetaT*SinThetaT);
		Vector R4 = n * ray_light.direction() - vec_normal * (n * CosThetaI + CosThetaT);
		R4.Normalize();

		// // Beer's Law
		// Color absorbance = object->GetMaterial()->GetColor()*0.15*dist1*(-1.0);
		// Color transparency = Color( exp(absorbance.x), exp(absorbance.y), exp(absorbance.z) );
		// color += refr_color*transparency;
	}
	else
		printf("(!) Refraction < 1.0\n");

	return coeff_beer;
}



void Material::Print() const
{
	printf(" [%d]", type());
	printf(" reflect{%.2f} ", coeff_reflect());
	color_refract().Print();
	printf(" refract{%.2f} ", coeff_refract());
	color_refract().Print();
	printf(" spec:{%.2f} rug:{%.2f}", specular(), rugosity());
}
}
